/**
 *
 */
package org.codetranslators.tools.visualization;

import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.*;
import java.util.*;

import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.event.*;
import javax.swing.filechooser.FileFilter;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.text.Document;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.undo.*;

import org.codetranslators.common.*;
import org.codetranslators.common.optimization.DominatorCalculationContext;
import org.codetranslators.compiler.abstractassembly.AssemType;
import org.codetranslators.compiler.canon.Linearizer;
import org.codetranslators.compiler.intermrep.AssemblyInstruction;
import org.codetranslators.compiler.intermrep.CodeGenerator;
import org.codetranslators.compiler.tiger.Debug;
import org.codetranslators.compiler.tiger.ErrorHandler;
import org.codetranslators.compiler.tiger.abssyntree.*;
import org.codetranslators.compiler.tiger.lexer.Lexer;
import org.codetranslators.compiler.tiger.semantics.Level;
import org.codetranslators.compiler.tiger.semantics.SemanticAnalyzer;
import org.codetranslators.tools.XMLUtils.CFGXMLConverter;
import org.codetranslators.tools.XMLUtils.XmlReader;
import org.codetranslators.tools.visualization.components.DDominatorTree;
import org.codetranslators.tools.visualization.components.DomGraph;

//import com.sun.java.swing.plaf.windows.TMSchema.Control;

/**
 * @author ramarao
 *
 */
public final class CompilerScope implements ChangeListener, ActionListener {

	private String version;
	private JFrame mainFrame;
	private JLabel statusMessage;
	private JLabel clientProperty;
	private DominatorTree dt;

	JButton generate;
	private boolean generateCFG = true;

	private String previousLocation = null;
	private File openedFile = null;

	private static final int CODE_SAMPLE_TAB_INDEX = 0;
	private static final int XML_INDEX = 1;
	private static final int CONTROL_FLOW_GRAPH_INDEX = 2;

	private boolean fileEdited;
	private JComponent selectedComponent;

	Vector<ControlFlowGraph> generatedCFGs;

	private boolean readFromXMl = false;

	public boolean isReadFromXMl() {
		return readFromXMl;
	}

	public void setReadFromXMl(boolean readFromXMl) {
		this.readFromXMl = readFromXMl;
	}

	private AbstractAction exitAction = new AbstractAction() {
		private static final long serialVersionUID = 0L;
		boolean enable = true;

		@Override
		public boolean isEnabled() {
			return enable;
		}

		@Override
		public void setEnabled(boolean b) {
			enable = b;
		}

		public void actionPerformed(ActionEvent e) {
			if (mainFrame != null) {
				mainFrame.dispose();
			}

		}

	};

	private AbstractAction generateCFGAction = new AbstractAction() {

		private static final long serialVersionUID = 0L;

		public void actionPerformed(ActionEvent e) {
			generateCFG = false;
			if (codeTextPane.getText() == null
					|| codeTextPane.getText().isEmpty()) {
				postStatusMessage("Please Enter some text");
				generateCFG = true;
				controlFlowGraphPane.cleanUp();
				JOptionPane.showMessageDialog(mainFrame, "Please Enter some text", "Error", JOptionPane.ERROR_MESSAGE);
				keepCodeTextPaneFocused();
				return;
			}

			System.out.println(readFromXMl);
			if (readFromXMl == true)
				generatedCFGs = getControlFlowGraphFromXML();
			else
				generatedCFGs = getControlFlowGraph();

			if (generatedCFGs == null || generatedCFGs.isEmpty())
			{
				controlFlowGraphPane.cleanUp();
				generateCFG = true;
				postStatusMessage("Compile Error. Please check the code");
				JOptionPane.showMessageDialog(mainFrame, "Compile Error. Please check the code" , "Error", JOptionPane.ERROR_MESSAGE);
				keepCodeTextPaneFocused();
				return;
			}

			CFGXMLConverter cfgConverter = new CFGXMLConverter();
			cfgConverter.generatetXML(generatedCFGs);

			if (generatedCFGs == null || generatedCFGs.isEmpty()) {
				postStatusMessage("Exception while converting CFG to xml.");
				JOptionPane.showMessageDialog(mainFrame, "Exception while converting CFG to xml." , "Error", JOptionPane.ERROR_MESSAGE);
				keepCodeTextPaneFocused();
				generateCFG = true;
				return;
			}

			for (ControlFlowGraph graph : generatedCFGs) {
				graph.displayFlowGraph();

			}
			controlFlowGraphPane.setCfg(generatedCFGs);
			controlFlowGraphPane.setRecalculate(true);
			postStatusMessage("Control flow graph generated successfully.");
		}
	};

	private AbstractAction showConsoleACtion = new AbstractAction() {

		public void actionPerformed(ActionEvent e) {

			if (((JCheckBoxMenuItem) e.getSource()).isSelected()) {
				addConsole(true);
			} else {
				removeConsole();
			}
		}

	};

	private JPanel codePanel;
	private JToolBar codePanelToolbar;
	private UndoableTextPane codeTextPane;
	private JTextArea consoleOutput;
	private JScrollPane console;
	private JPanel xmlPanel;
	private CFGPanel controlFlowGraphPane;
	private JTabbedPane tabbedPane;
	private DockingFrame dockingFrame;
	private JButton interferenceGraphButton;
	private JButton dominatorTreeButton;
	private JMenuItem interferenceGraphMenuItem;
	private JMenuItem dominatorTreeMenuItem;
	private JButton openButton;
	private JButton saveButton;
	private JButton saveAsButton;

	CompilerScope(String version) {

		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception e) {
		}

		this.version = version;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		CompilerScope cs = new CompilerScope("1.0");
		cs.buildWindow();
		cs.show();
	}

	private void buildWindow() {
		mainFrame = new JFrame("Compiler Scope - " + version);
		mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		addContentPanel();
		addToolbar();
		addMenubar();
		addStatusPanel();
		addConsole(true);
	}

	void addMenubar() {
		JMenuBar menuBar = new JMenuBar();

		JMenu fileMenu = new JMenu("File");
		fileMenu.setMnemonic('f');

		JMenuItem open = new JMenuItem("Open", 'O');
		open.addActionListener(this);
		open.setActionCommand("open");
		fileMenu.add(open);
		fileMenu.addSeparator();

		JMenuItem save = new JMenuItem("Save", 'S');
		save.addActionListener(this);
		save.setActionCommand("save");
		fileMenu.add(save);

		JMenuItem saveAs = new JMenuItem("Save As", 'A');
		saveAs.addActionListener(this);
		saveAs.setActionCommand("saveas");
		fileMenu.add(saveAs);

		fileMenu.addSeparator();

		JMenuItem menuItem = new JMenuItem(exitAction);
		menuItem.setText("Exit");
		menuItem.setMnemonic('x');

		fileMenu.add(menuItem);

		JMenu viewMenu = new JMenu("View");
		viewMenu.setMnemonic('V');

		JCheckBoxMenuItem showGenerateButton = new JCheckBoxMenuItem(
				"Show Generate CFG");
		showGenerateButton.setActionCommand("ShowGenerateCFG");
		showGenerateButton.addActionListener(this);
//		viewMenu.add(showGenerateButton);

		JCheckBoxMenuItem showLowerPane = new JCheckBoxMenuItem(
				"Console");
		showLowerPane.setActionCommand("ShowLowerPane");
		showLowerPane.addActionListener(this);
		viewMenu.add(showLowerPane);

		interferenceGraphMenuItem = new JMenuItem("Interference Graph");
		interferenceGraphMenuItem
				.addActionListener(this.interferenceGraphButton
						.getActionListeners()[0]);
		interferenceGraphMenuItem.setActionCommand(interferenceGraphButton
				.getActionCommand());

		viewMenu.add(interferenceGraphMenuItem);

		dominatorTreeMenuItem = new JMenuItem("Dominator Tree");
		dominatorTreeMenuItem.addActionListener(this.dominatorTreeButton
				.getActionListeners()[0]);
		dominatorTreeMenuItem.setActionCommand(dominatorTreeButton
				.getActionCommand());
		viewMenu.add(dominatorTreeMenuItem);

		menuBar.add(fileMenu);
		menuBar.add(viewMenu);
		mainFrame.setJMenuBar(menuBar);
	}

	void addToolbar() {
		JToolBar toolBar = new JToolBar();

		Icon icon = new ImageIcon("resources/images/open.png");
		openButton = new JButton(icon);
		openButton.setSize(16,16);
		openButton.setToolTipText("Open");
		openButton.addActionListener(this);
		openButton.setActionCommand("open");
		openButton.setMnemonic('o');
		openButton.registerKeyboardAction(this, "open",KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);
		toolBar.add(openButton);

		saveButton = new JButton(new ImageIcon("resources/images/save.png"));
		saveButton.setSize(16,16);
		saveButton.setToolTipText("Save");
		saveButton.addActionListener(this);
		saveButton.setActionCommand("save");
		saveButton.setMnemonic('s');
		saveButton.registerKeyboardAction(this, "save",KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);
		saveButton.setEnabled(false);
		toolBar.add(saveButton);

		saveAsButton = new JButton(new ImageIcon(
				"resources/images/saveas.png"));
		saveAsButton.setSize(16,16);
		saveAsButton.setToolTipText("Save As");
		saveAsButton.addActionListener(this);
		saveAsButton.setActionCommand("saveas");
		saveAsButton.setMnemonic('A');
		toolBar.add(saveAsButton);

		dominatorTreeButton = new JButton(new ImageIcon(
				"resources/images/dt.png"));
		dominatorTreeButton.setToolTipText("Dominator Tree");
		dominatorTreeButton.setSize(dominatorTreeButton.getPreferredSize());
		dominatorTreeButton.addActionListener(controlFlowGraphPane);
		dominatorTreeButton.setActionCommand("DominatorTree");
		dominatorTreeButton.setEnabled(false);
		toolBar.add(dominatorTreeButton);

		interferenceGraphButton = new JButton(new ImageIcon(
				"resources/images/ig2.png"));
		interferenceGraphButton.setToolTipText("Interference Graph");
		interferenceGraphButton.setSize(dominatorTreeButton.getPreferredSize());
		interferenceGraphButton.setActionCommand("InterferenceGraph");
		interferenceGraphButton.addActionListener(controlFlowGraphPane);
		interferenceGraphButton.setEnabled(false);
		toolBar.add(interferenceGraphButton);

		toolBar.setBounds(0, 0, mainFrame.getWidth() - 20, 50);
		toolBar.setFloatable(false);
		mainFrame.getContentPane().add(toolBar, BorderLayout.NORTH);
	}

	void addContentPanel() {

		buildCodePanel();

		// Create the panel for the xml view
		xmlPanel = new JPanel();
		xmlPanel.setBackground(Color.white);
		xmlPanel.setLayout(new BorderLayout());

		JTextPane xmlPane = new JTextPane();
		xmlPanel.add(xmlPane);
		final HTMLEditorKit editorKit = new HTMLEditorKit();
		editorKit.install(xmlPane);
		xmlPane.setEditorKit(editorKit);
		// xmlPane.setEditable(false);
		// xmlPane.setFocusable(false);

		// Create the panel for the cfg view
		controlFlowGraphPane = new CFGPanel();

		dockingFrame = new DockingFrame("DockingFrame");
		adddocks();
		mainFrame.getContentPane().add(dockingFrame);
	}

	void adddocks() {
		codePanel.addFocusListener(new FocusAdapter() {

			@Override
			public void focusGained(FocusEvent e) {
				selectedComponent = codePanel;
			}

		});
		selectedComponent = codePanel;
		controlFlowGraphPane.addFocusListener(new FocusAdapter() {

			@Override
			public void focusGained(FocusEvent e) {
				selectedComponent = controlFlowGraphPane;
				generateCFG();
			}
		});

		dockingFrame.add(codePanel, "Code Sample", DockingFrame.LEFT);
		dockingFrame.add(controlFlowGraphPane, "Control Flow Graph",
				DockingFrame.LEFT);
	}

	void addStatusPanel() {
		JPanel statusPanel = new JPanel(new BorderLayout());
		statusPanel.setBounds(0, 0, mainFrame.getWidth() - 10, 45);
		statusMessage = new JLabel("Status Message Bar", JLabel.LEFT);
		statusPanel.add(statusMessage);
		statusMessage.setFocusable(false);
		statusPanel.setBounds(0, 0, mainFrame.getWidth() - 60, 40);
		clientProperty = new JLabel("Writable");
		clientProperty.setBorder(BorderFactory.createLineBorder(clientProperty
				.getForeground()));
		clientProperty.setBounds(mainFrame.getWidth() - 60, 0, 50, 30);
		clientProperty.setFocusable(false);
		statusPanel.add(clientProperty, BorderLayout.EAST);
		statusPanel.setBorder(BorderFactory.createEtchedBorder());
		statusPanel.setFocusable(false);
		mainFrame.getContentPane().add(statusPanel, BorderLayout.SOUTH);
	}

	protected void postStatusMessage(String message) {
		statusMessage.setText(message);
	}

	protected void updateClientProperty(String value) {
		clientProperty.setText(value);
		clientProperty.getParent().repaint();
	}

	protected void updateGUIComponents() {
		if (selectedComponent != null) {
			if (selectedComponent.equals(controlFlowGraphPane)) {

				updateClientProperty("Read Only");
				interferenceGraphButton.setEnabled(true);
				interferenceGraphMenuItem.setEnabled(true);
				dominatorTreeButton.setEnabled(true);
				dominatorTreeMenuItem.setEnabled(true);
			}
		} else {
			interferenceGraphButton.setEnabled(false);
			dominatorTreeButton.setEnabled(false);
			interferenceGraphMenuItem.setEnabled(false);
			dominatorTreeMenuItem.setEnabled(false);
		}

	}

	void show() {
		Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
		mainFrame.setSize(dim.width, dim.height - 25);
//		keepCenter();
		mainFrame.setVisible(true);
		dockingFrame.updateDividerPosition();
	}

	void keepCenter() {
		final Dimension screenSize = Toolkit.getDefaultToolkit()
				.getScreenSize();
		final Dimension applicationSize = mainFrame.getSize();
		final int x = Math.abs((screenSize.width - applicationSize.width) / 2);
		final int y = Math
				.abs((screenSize.height - applicationSize.height) / 2);
		mainFrame.setLocation(x, y);
	}

	void buildCodePanel() {
		// Create the panel for the code view
		codePanel = new JPanel();
		codePanel.setLayout(new BorderLayout());
		generate = new JButton("Generate CFG");
		generate.setSize(generate.getPreferredSize());
		generate.addActionListener(generateCFGAction);

		codePanelToolbar = new JToolBar();
		codePanelToolbar.add(generate);
		codePanelToolbar.setFloatable(false);
		//codePanel.add(codePanelToolbar, BorderLayout.NORTH);

		final LineNr nr = new LineNr();

		if (codeTextPane == null)
			return;

		codeTextPane.setSize(codeTextPane.getMaximumSize());
		codePanel.addFocusListener(new FocusAdapter() {
			@Override
			public void focusGained(FocusEvent e) {
				updateClientProperty("Writable");
				codeTextPane.requestFocus();
			}
		});
		codeTextPane.getDocument().addDocumentListener(new MyDocumentListener());
		codeTextPane.registerKeyboardAction(this, "save",KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK), JComponent.WHEN_FOCUSED);
		nr.addToPanel(codePanel);
	}

	void addConsole(boolean showNow) {
		if (console == null) {
			consoleOutput = new JTextArea();
			console = new JScrollPane(consoleOutput);
			System.setErr(new PrintStream(new ComponentOutputStream(
					consoleOutput)));
			System.setOut(new PrintStream(new ComponentOutputStream(
					consoleOutput)));
		}
		if (showNow)
			dockingFrame.add(console, "Console", DockingFrame.BOTTOM);
	}

	void removeConsole() {
		if (consoleOutput != null) {
			dockingFrame.remove(console);
		}
	}

	void postMessageOnConsole(final String messsage) {
		consoleOutput.append(messsage);
	}

	public void stateChanged(ChangeEvent e) {
		showConsoleACtion
				.setEnabled(tabbedPane.getSelectedIndex() == CODE_SAMPLE_TAB_INDEX);
	}

	private Vector<ControlFlowGraph> getControlFlowGraph() {

		Temp.reset();

		Vector<ControlFlowGraph> cfgs = new Vector<ControlFlowGraph>(); // List
		// of
		// cfgs
		try {
			// Get the text from the code text pane
			String codeText = codeTextPane.getText();
			CharArrayReader strReader = new CharArrayReader(codeText
					.toCharArray());

			String filename = "VisualizationTest.tig";

			System.out.println("File: " + filename);

			// Generate name of the output file
			File inFile = new File(filename);
			String inFileName = inFile.getName();
			int periodPos = inFileName.indexOf(".");
			String outFileNameInterim = inFileName.substring(0, periodPos)
					+ "_intrm.s"; // for intermediate result

			String outFileName = inFileName.substring(0, periodPos) + ".s"; // for
			// final
			// code
			// after
			// register
			// allocation

			File outFile = new File(outFileNameInterim);

			// Lexical analysis and parsing
			TigerParser tp = new TigerParser(new Lexer(strReader));
			Object result = tp.parse().value;

			// Semantic analysis
			System.out.println("Completed generating abstract syntax tree");
			SemanticAnalyzer semantAnalyzer = new SemanticAnalyzer();

			Vector<?> functionLevels = semantAnalyzer
					.translateAbstractTree((Absyn) result);
			ErrorHandler errorHandler = ErrorHandler.getInstance();
			errorHandler.displayResult();

			// Intermediate code generation
			Debug debug = new Debug();
			if (errorHandler.getNumErrors() != 0)
				return null;

			// No errors in semantic analysis; continue with intermediate code
			// generation
			// for each function

			Vector<Object> intermediateCodeListing = new Vector<Object>();
			Vector<Object> finalCodeListing = new Vector<Object>();

			boolean compiledSuccessfully = true;
			int numFuncs = functionLevels.size();
			HashMap<Object, Object> fNameVsNumRegsUsed = new HashMap<Object, Object>();
			Vector<Object> commonData = new Vector<Object>();

			for (int i = 0; i < numFuncs; i++) {
				Level fLevel = (Level) functionLevels.elementAt(i);
				String functionName = fLevel.getLevelName().toString();
				if (fLevel != null) {
					AssemType body = fLevel.getFunctionBody();
					if (body != null) {
						System.out.println("FUNCTION:");
						// debug.printAssem(body);
						Linearizer linearizer = processWithLinearizer(debug,
								body, fLevel.getLevelName());

						// Generate assembly code

						CodeGenerator codeGenerator = new CodeGenerator();
						codeGenerator.generateCode(linearizer.getTrace());
						Vector<Object> instList = codeGenerator
								.getInstructionsList();
						intermediateCodeListing.addAll(instList);
						writeInstructionsToFile(outFile,
								intermediateCodeListing);

						// Create a control flow graph from the instructions
						// created above
						ControlFlowGraph flowGraph = new ControlFlowGraph(
								instList, false);
						cfgs.add(flowGraph);
//						System.out.println("constructinf dominator Tree------------");
//						DominatorTree dominatorTree = new DominatorCalculationContext(flowGraph,flowGraph.getStartNode()).getDominatorTree();
//						DDominatorTree dDomiatorTree = new DDominatorTree(dominatorTree);
//						dDomiatorTree.constructDominatorTreeDisplayInfo();
//						System.out.println("displaying the  dominator Tree-- nodes----------");
//						dDomiatorTree.getDomGraph().display();
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return cfgs; // Return the first cfg found
	}

	private Linearizer processWithLinearizer(Debug debug, AssemType body,
			Symbol levelName) {
		Linearizer linearizer = new Linearizer(levelName.toString());
		System.out.println("AFTER CANONIZING WITH LINEARIZER:");
		linearizer.linearize(body);
		debug.print(linearizer.getCanonized());

		System.out.println("BASIC BLOCKS WITH LIST GENERATED FROM LINEARIZER:");
		linearizer.generateBasicBlocks();
		debug.print(linearizer.getBasicBlocks());

		System.out.println("TRACE SCHEDULE WITH LINEARIZER:");
		linearizer.generateTrace();
		debug.print(linearizer.getTrace());

		return linearizer;
	}

	private void writeInstructionsToFile(File outFile, Vector instList) {
		try {
			FileWriter fileWriter = new FileWriter(outFile);
			int instNum = instList.size();
			for (int i = 0; i < instNum; i++) {
				AssemblyInstruction instr = (AssemblyInstruction) instList
						.elementAt(i);
				String linenum = "" + i + ") ";
				String str = linenum + instr.getAssemCode(false);
				fileWriter.write(str);
			}
			fileWriter.flush();
			fileWriter.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public Vector<ControlFlowGraph> getControlFlowGraphFromXML() {

		try {
			String codeText = codeTextPane.getText();
			String fileName = "input.xml";

			File inFile = new File(fileName);
			FileOutputStream file = new FileOutputStream(inFile);
			file.write(codeText.getBytes());

			XmlReader reader = new XmlReader();

			return reader.readXml(fileName);
		} catch (Exception ex) {

		}

		return null;
	}


	class CFGPanel extends JPanel implements
			PropertyChangeListener, ActionListener, TreeSelectionListener {
		private static final long serialVersionUID = 1L;
		private Vector<ControlFlowGraph> cfgs = new Vector<ControlFlowGraph>();
		private boolean recalculate;

		JSplitPane splitPane1;
		JSplitPane splitPane2;
		Vector<String> data;
		JTree treeOfCFGs;
		JPanel leftPanel;
		JPanel cardPanel;
		JPanel rightPanel;
		JTable table;
		CardLayout cardLayout;
		int dividerPos = 0;

		public CFGPanel() {
			setLayout(new BorderLayout());
			splitPane1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
			splitPane1.setDividerSize(3);

			splitPane2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
			splitPane2.setDividerSize(3);

			data = new Vector<String>();
			treeOfCFGs = new JTree(new DefaultMutableTreeNode("Functions"));
			treeOfCFGs.addTreeSelectionListener(this);
			treeOfCFGs.setRootVisible(true);
			Font font = treeOfCFGs.getFont();
			treeOfCFGs.setFont(new Font(font.getName(), Font.BOLD, font
					.getSize() + 1));
			leftPanel = new JPanel();
			leftPanel.setBackground(Color.white);
			leftPanel.add(treeOfCFGs);
			cardLayout = new CardLayout();
			cardPanel = new JPanel(cardLayout);
			splitPane2.add(cardPanel, JSplitPane.LEFT);

			rightPanel = new JPanel();
			splitPane1.add(splitPane2, JSplitPane.RIGHT);

			buildRightPanel();
			add(splitPane1);
		}


		public void setCfg(Vector<ControlFlowGraph> cfgs) {
			this.cfgs = cfgs;
		}


		void buildRightPanel()
		{
			rightPanel.setLayout(new BorderLayout());
			Vector<String> columnNames = new Vector<String>();
			columnNames.add("Attribute");
			columnNames.add("Value");
			DefaultTableModel tableModel = new DefaultTableModel(columnNames, 3);
			table = new JTable(tableModel);
			table.setEnabled(false);
			table.setFocusable(false);
			table.setSelectionBackground(Color.GRAY);

			Action hideAction = new AbstractAction(){
				@Override
				public void actionPerformed(ActionEvent e) {
					hideRightPanel();
				}

			};

			JButton hideButton = new JButton(hideAction);
			hideButton.setText("Hide");
			hideButton.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
			hideButton.setBackground(Color.WHITE);
			hideButton.setOpaque(true);
			hideButton.setBorderPainted(true);
			JToolBar toolBar = new JToolBar();
			toolBar.setBackground(Color.WHITE);
			toolBar.setFloatable(false);
			toolBar.add(hideButton);

			rightPanel.add(toolBar, BorderLayout.NORTH);
			JScrollPane scrollPane = new JScrollPane(table);
			scrollPane.getViewport().setBackground(Color.WHITE);
			rightPanel.add(scrollPane);
			rightPanel.registerKeyboardAction(hideAction, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
		}


		void showRightPanel()
		{
			splitPane2.add(rightPanel, JSplitPane.RIGHT);
			splitPane2.setDividerLocation(0.8);
		}


		void hideRightPanel()
		{
			splitPane2.remove(rightPanel);
		}


		void updateDataToTable(Vector<String> rowData)
		{
			DefaultTableModel model = (DefaultTableModel)table.getModel();
			Vector<String> col1 = new Vector<String>();
			col1.add("Name");
			col1.add("Dominance Frontiers");
			col1.add("Immediate Dominator");
			for(int i =0;i<rowData.size(); i++)
			{
				model.setValueAt(col1.get(i), i, 0);
				model.setValueAt(rowData.get(i), i, 1);
			}
			table.updateUI();
		}


		public void setRecalculate(boolean b) {
			recalculate = b;
			if (!recalculate || cfgs == null || cfgs.isEmpty())
				return;
			data.clear();
			cardPanel.removeAll();
			hideRightPanel();
			GUIMediator mediator;
			JScrollPane scrollPane;
			DefaultTreeModel treeModel = (DefaultTreeModel)treeOfCFGs.getModel();
			DefaultMutableTreeNode rootNode = (DefaultMutableTreeNode)treeModel.getRoot();
			rootNode.removeAllChildren();
			for (ControlFlowGraph cfg : cfgs) {
				mediator = new GUIMediator();
				mediator.setCFG(cfg);
				mediator.setDT(createDominatorTree(cfg));
				mediator.generateDominatorFrontiers();
				mediator.addPropertyChangeListener(this);
				scrollPane = mediator.getComponent();
				scrollPane.getViewport().setBackground(Color.white);
				cardPanel.add(scrollPane, cfg.getStartNode().getName());
				data.add(cfg.getStartNode().getName());
				rootNode.add(new DefaultMutableTreeNode(cfg.getStartNode().getName()));
			}
			SwingUtilities.invokeLater(new Runnable()
			{
				@Override
				public void run() {
					if (treeOfCFGs.getRowCount() > 1)
					{
						treeOfCFGs.setSelectionInterval(1, 1);
					}
				}
			});
		}


		private void updateSplitPosition() {
			if (!recalculate)
				return;

			treeOfCFGs.updateUI();

			if (data.isEmpty()) {
				splitPane1.remove(leftPanel);
				hideRightPanel();
			} else {
				splitPane1.add(leftPanel, JSplitPane.LEFT);
				dividerPos = (int) ((double) (splitPane1.getWidth() - splitPane1
						.getDividerSize())
						* (double) treeOfCFGs.getPreferredSize().getWidth() / (double) cardPanel
						.getWidth());

				splitPane1.setDividerLocation(dividerPos);
			}
			recalculate = false;
		}

		@Override
		public void paint(Graphics g) {
			super.paint(g);
			updateSplitPosition();
		}


		public void propertyChange(PropertyChangeEvent evt) {
			if (evt.getPropertyName().equals("DISPLAYPROPERTY")) {
				updateDataToTable((Vector<String>) evt.getNewValue());
				showRightPanel();
			}
			if (evt.getPropertyName().equals("HIDEPROPERTY")) {
				hideRightPanel();
			}

		}


		public boolean isEmpty() {
			return treeOfCFGs.getRowCount() <= 0;
		}


		public void cleanUp()
		{
			data.clear();
			treeOfCFGs.removeSelectionInterval(0, treeOfCFGs.getRowCount());
			cardPanel.removeAll();
			postStatusMessage("");
			recalculate = true;
			updateSplitPosition();
			repaint();
			recalculate = false;
		}


		public void actionPerformed(ActionEvent event) {
			//System.out.println("action performed is "+event.getActionCommand());
			if (event.getActionCommand().equals("InterferenceGraph")) {
				System.out.println("action performed is "+event.getActionCommand());
				GraphWindow graphWindow = null;

				if (treeOfCFGs.getLeadSelectionRow() < 1)
				{
					JOptionPane.showMessageDialog(mainFrame,
					"Please select one of the CFGs generated.");
					return;
				}

				// Added by Shreesha -> Create cfg with one instruction per node
				// and use that to create the interference graph
				ControlFlowGraph chosenCFG = cfgs.get(treeOfCFGs.getLeadSelectionRow() - 1);
				CFGLinearizationDFS cfgLinearizationDFS = new CFGLinearizationDFS();
				Vector<AssemblyInstruction> instrs = ((Vector<AssemblyInstruction>)
						cfgLinearizationDFS.execute(chosenCFG, chosenCFG.getStartNode()));

				writeInstructionsToFile(new File("outfile.txt"), instrs);

				ControlFlowGraph flowGraph = new ControlFlowGraph(instrs, true);

				InterferenceGraph ig = new InterferenceGraph((flowGraph));

				ig.saveInterferenceGraphInFile(new File("ig_outfile.txt"));

				graphWindow = new GraphWindow(ig);

				if (graphWindow == null)
					return;

				graphWindow.applyAlgorithm("Spring");
				graphWindow.setVisible(true);
			}
			else if (event.getActionCommand().equals("DominatorTree"))
			{

				if (treeOfCFGs.getLeadSelectionRow() < 1)
				{
					JOptionPane.showMessageDialog(mainFrame,
					"Please select one of the CFGs generated.");
					return;
				}

				GraphWindow graphWindow = null;
				dt = createDominatorTree(cfgs.get(treeOfCFGs.getLeadSelectionRow() - 1));
				DDominatorTree dDominatorTree = new DDominatorTree(dt);
				dDominatorTree.constructDominatorTreeDisplayInfo();
				DomGraph domGraph = dDominatorTree.getDomGraph();
				domGraph.display();
				graphWindow = new GraphWindow(domGraph);

				if(graphWindow!=null){
					graphWindow.applyAlgorithm("Tree");
					graphWindow.setVisible(true);
				}
			}
		}

		@Override
		public void valueChanged(TreeSelectionEvent e) {
			if (treeOfCFGs.getRowCount() > 0 && treeOfCFGs.getSelectionCount() > 0)
				cardLayout.show(cardPanel, treeOfCFGs.getSelectionPath().getLastPathComponent().toString());
		}

	}

	private DominatorTree createDominatorTree(ControlFlowGraph chosenCFG)
	{
		DominatorCalculationContext dcc = new DominatorCalculationContext(chosenCFG, chosenCFG.getStartNode());
		return dcc.getDominatorTree();
	}


	class ComponentOutputStream extends OutputStream {

		protected byte buf[];
		protected int count;

		JTextArea textComponent;

		ComponentOutputStream(JTextArea textComponent) {
			this.textComponent = textComponent;
			buf = new byte[80];
		}

		@Override
		public void write(int b) throws IOException {
			int newcount = count + 1;
			if (newcount > buf.length) {
				buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
			}
			buf[count] = (byte) b;
			count = newcount;

			if (b == '\n' || count == (buf.length - 1)) {
				textComponent.append(new String(buf, 0, count));
				count = 0;
			}
		}

	}

	protected void showCodePanelToolbar(boolean show) {
		if (show) {
			codePanel.add(codePanelToolbar, BorderLayout.NORTH);
		} else
			codePanel.remove(codePanelToolbar);
	}

	public void actionPerformed(ActionEvent event) {
		if (event.getActionCommand().equals("ShowGenerateCFG")) {
			showCodePanelToolbar(((JCheckBoxMenuItem) event.getSource())
					.isSelected());
		} else if (event.getActionCommand().equals("ShowLowerPane")) {
			dockingFrame.showLowerPanel(((JCheckBoxMenuItem) event.getSource())
					.isSelected());
		}

		else if (event.getActionCommand().equals("open")) {
			readFromFile();
		}
		else if (event.getActionCommand().equals("saveas"))
		{
			saveToFile();
		}
		else if (event.getActionCommand().equals("save"))
		{
			if (fileEdited || openedFile == null)
				saveFile();
		}
	}

	private void readFromFile() {
		JFileChooser fd = null;
		try {
			fd = new JFileChooser(previousLocation);
			fd.setFileFilter(new FileFilter() {
				@Override
				public boolean accept(File f) {
					if (f.isDirectory() || f.getName().endsWith(".xml")
							|| f.getName().endsWith(".tig")) {
						return true;
					}

					return false;
				}

				@Override
				public String getDescription() {
					return "XML, tig files";
				}

			});
			if (fd.showOpenDialog(mainFrame) != JFileChooser.APPROVE_OPTION)
			{
				return;
			}
		} catch (Throwable e) {
			JOptionPane.showMessageDialog(mainFrame,
					"It appears your VM does not allow file loading.");
			return;
		}
		openedFile = fd.getSelectedFile();

		if (openedFile == null)
			return;

		previousLocation = openedFile.getParent();
		try {
			BufferedReader br = new BufferedReader(new FileReader(openedFile));
			StringBuffer fileText = new StringBuffer();
			String text = br.readLine();
			while (text != null) {
				fileText.append(text);
				fileText.append("\n");
				text = br.readLine();
			}
			codeTextPane.setText(fileText.toString());
			codeTextPane.requestFocus();
			br.close();
			setFileModified(false);
			generateCFG = true;

			if (selectedComponent == controlFlowGraphPane)
			{
				generateCFG();
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	protected void saveToFile() {
		JFileChooser fd = null;
		postStatusMessage("Save As...");
		try {
			fd = new JFileChooser(previousLocation);
			fd.setFileFilter(new FileFilter() {
				@Override
				public boolean accept(File f) {
					if (f.isDirectory() || f.getName().endsWith(".xml")
							|| f.getName().endsWith(".tig")) {
						return true;
					}

					return false;
				}

				@Override
				public String getDescription() {
					return "XML, tig files";
				}

			});
			fd.setDialogTitle("Save As...");
			if (fd.showSaveDialog(mainFrame) != JFileChooser.APPROVE_OPTION)
			{
				postStatusMessage("");
				return;
			}
		} catch (Throwable e) {
			JOptionPane.showMessageDialog(mainFrame,
					"It appears your VM does not allow file saving.");
			postStatusMessage("");
			return;
		}
		File file = fd.getSelectedFile();

		if (file != null)
			try {
				String filePath = file.getPath();
				if (filePath.indexOf('.') == -1)
					filePath += ".xml";
				File createFile = new File(filePath);
				if (!createFile.createNewFile())
				{
					int result = JOptionPane.showConfirmDialog(mainFrame,
					"Do you want to replace the existing file ?.", "Overwrite", JOptionPane.YES_NO_OPTION);
					if (result != JOptionPane.YES_OPTION)
						return;
				}
				previousLocation = createFile.getParent();
				BufferedWriter bw = new BufferedWriter(new FileWriter(createFile));
				String text = codeTextPane.getText();
				bw.write(text);
				bw.close();
				openedFile = file;
				setFileModified(false);
				generateCFG = true;
			} catch (IOException e) {
				e.printStackTrace();
			}

	}

	protected void saveFile() {
		if (openedFile != null)
		{
			try {
				postStatusMessage("Saved the file...");
				previousLocation = openedFile.getParent();
				BufferedWriter bw = new BufferedWriter(new FileWriter(openedFile));
				String text = codeTextPane.getText();
				bw.write(text);
				bw.close();
				setFileModified(false);
				generateCFG = true;
				changeTitle(codePanel, "Code Sample - "+ openedFile.getName());
			} catch (IOException e) {
				e.printStackTrace();
				JOptionPane.showMessageDialog(mainFrame,
						"Unable to write the file!");
			}
		}
		else
			saveToFile();
	}

	public class LineNr extends JPanel {
		// for this simple experiment, we keep the pane + scrollpane as members.
		JScrollPane scrollPane;

		public LineNr() {
			super();
			setMinimumSize(new Dimension(30, 30));
			setPreferredSize(new Dimension(30, 30));
			setMinimumSize(new Dimension(30, 30));
			codeTextPane = new UndoableTextPane() // we need to override paint so that the
			// linenumbers stay in sync
			{
				public void paint(Graphics g) {
					LineNr.this.repaint();
					super.paint(g);
				}
			};
			scrollPane = new JScrollPane(codeTextPane);

		}

		public void addToPanel(JComponent component)
		{
			component.add(this, BorderLayout.WEST);
			component.add(scrollPane, BorderLayout.CENTER);
		}

		public void paint(Graphics g) {
			super.paint(g);

			// We need to properly convert the points to match the viewport
			// Read docs for viewport
			int start = codeTextPane.viewToModel(scrollPane.getViewport()
					.getViewPosition()); // starting pos in document
			int end = codeTextPane.viewToModel(new Point(scrollPane.getViewport()
					.getViewPosition().x
					+ codeTextPane.getWidth(), scrollPane.getViewport()
					.getViewPosition().y
					+ codeTextPane.getHeight()));
			// end pos in doc

			// translate offsets to lines
			Document doc = codeTextPane.getDocument();
			int startline = doc.getDefaultRootElement().getElementIndex(start);
			int endline = doc.getDefaultRootElement().getElementIndex(end) + 1;

			int fontHeight = g.getFontMetrics(codeTextPane.getFont()).getHeight(); // font
			// height

			for (int line = startline, y = 0; line <= endline; line++, y += fontHeight) {
				g.drawString(Integer.toString(line), 0, y);
			}

		}
	}


	private void generateCFG()
	{
		if(generateCFG)
		{
			generate.doClick();
			if (!generateCFG)
				selectedComponent = controlFlowGraphPane;
			updateGUIComponents();
		}
	}

	class MyDocumentListener implements DocumentListener
	{

		@Override
		public void changedUpdate(DocumentEvent e) {
			setFileModified(true);
		}

		@Override
		public void insertUpdate(DocumentEvent e) {
			setFileModified(true);
		}

		@Override
		public void removeUpdate(DocumentEvent e) {
			setFileModified(true);
		}

	}

	public void setFileModified(boolean modified)
	{
		fileEdited = modified;
		generateCFG = modified;
		saveButton.setEnabled(modified);
		if (openedFile != null)
		{
			if (modified)
				changeTitle(codePanel, "Code Sample - "+ openedFile.getName()+"*");
			else
				changeTitle(codePanel, "Code Sample - "+ openedFile.getName());
		}
	}


	class UndoableTextPane extends JTextPane implements UndoableEditListener, FocusListener, KeyListener
	{
		private static final long serialVersionUID = 1L;

		//Setting Undo Limit to 1500 edits
	    public static final int UNDO_LIMIT = 1500;

	    //UndoManager
	    private UndoManager m_undoManager;


	    //constructor
	    public UndoableTextPane()
	    {
	        super();

	        //add the UndoableEditListener to the TextArea
	        getDocument().addUndoableEditListener(this);
	        //add the KeyListener
	        this.addKeyListener(this);
	        //add the FocusListener
	        this.addFocusListener(this);
	        createUndoMananger();
	    }

	    //createUndoMananger creating undo manager
	    private void createUndoMananger()
	    {
	    	if (m_undoManager == null)
	    	{
	    		m_undoManager = new UndoManager();
	    		m_undoManager.setLimit(UNDO_LIMIT);
	    	}
	    }

	    //removeUndoMananger removing undo manager
	    private void removeUndoMananger()
	    {
	        m_undoManager.end();
	    }

	    public void focusGained(FocusEvent fe)
	    {
	        //creating undo manager on focus gained
	        createUndoMananger();
	    }

	    public void focusLost(FocusEvent fe)
	    {
	        //removing undo manager on focus lose
//	        removeUndoMananger();
	    }

	    //undoableEditHappened called when edit happened
	    public void undoableEditHappened(UndoableEditEvent e)
	    {
	        //add the edits to the unod manager
	        m_undoManager.addEdit(e.getEdit());
	    }

	    public void keyPressed(KeyEvent e)
	    {
	        //identify the key pressed is the combination of
	        //Controlkey and Z key
	        if((e.getKeyCode() == KeyEvent.VK_Z) && (e.isControlDown()))
	        {
	            try
	            {
	                //Undo changes
	                m_undoManager.undo();
	            }
	            catch(CannotUndoException cue)
	            {
	                Toolkit.getDefaultToolkit().beep();
	            }
	        }

	        //identify the key pressed is the combination of
	        //Controlkey and Y key
	        if((e.getKeyCode() == KeyEvent.VK_Y) && (e.isControlDown()))
	        {
	            try
	            {
	                //Redo changes
	                m_undoManager.redo();
	            }
	            catch(CannotRedoException cue)
	            {
	                Toolkit.getDefaultToolkit().beep();
	            }
	        }
	    }

	    public void keyReleased(KeyEvent e)
	    {
	    }

	    public void keyTyped(KeyEvent e)
	    {
	    }
	}

	private void keepCodeTextPaneFocused()
	{
		JTabbedPane comp = (JTabbedPane)SwingUtilities.getAncestorOfClass(JTabbedPane.class,codePanel);
		int i = getIndexOfTab(codePanel);
		comp.setSelectedIndex(i == -1 ? 0 : i);
	}

	private void changeTitle(JComponent component, String title)
	{
		JTabbedPane comp = (JTabbedPane)SwingUtilities.getAncestorOfClass(JTabbedPane.class,component);
		int i = getIndexOfTab(component);
		if (i == -1)
			return;
		comp.setTitleAt(i, title);
	}

	private int getIndexOfTab(JComponent component)
	{
		JTabbedPane comp = (JTabbedPane)SwingUtilities.getAncestorOfClass(JTabbedPane.class,component);
		if (comp != null)
		{
			for (int i = 0; i<comp.getTabCount(); i++)
			{
				if (comp.getComponentAt(i)== component)
				{
					return i;
				}
			}
		}

		return -1;
	}
}
